package com.lx.websockt.web;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lx.websockt.bean.WebsocktPropertise;
import com.lx.websockt.biz.IMsgSender;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@RestController
@RequestMapping("ws")
// 地址 当浏览器链接服务器所需要的地址
@ServerEndpoint("/ws/{id}")
public class WebsocktDo {
    // 在每一次链接的时候 WebsocktDo 对象 都会被创建一次

    static WebsocktPropertise Propertise;
    static IMsgSender iMsgSender;
    static JdbcTemplate jdbcTemplate;

    @Autowired
    public void setiMsgSender(IMsgSender iMsgSender) {
        WebsocktDo.iMsgSender = iMsgSender;
    }

    @Autowired
    public void setPropertise(WebsocktPropertise propertise) {
        WebsocktDo.Propertise = propertise;
    }

    @Autowired
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        WebsocktDo.jdbcTemplate = jdbcTemplate;
    }

    @GetMapping("config")
    WebsocktPropertise websocktPropertise(){

        return Propertise;
    }

    // websocket 会为每个连接成功的客服端创建一个 talkdo 对象
    // 在线用户的容器
    private static Map<String, Session> onlines = new ConcurrentHashMap<>();

    // 链接成功执行的方法
    @OnOpen
    public void onOpen(Session session, @PathParam("id") String id) throws Exception {
        Object userinfo = getUserInfoById(id);
        session.getUserProperties().put("id", userinfo);
        onlines.put(id, session);
        Msg msg = buildMsg(userinfo, "上线了", true);
        iMsgSender.send(msg);
    }

    @OnClose
    public void OnClose(Session session) throws Exception {
        Map<String, Object> userinfo = (Map<String, Object>) session.getUserProperties().get("id");
        onlines.remove(userinfo.get(websocktPropertise().getKeyColumn()) + "");
        Msg msg = buildMsg(userinfo, "下线了", true);
        iMsgSender.send(msg);
    }

    @OnError
    public void OnError(Session session, Throwable throwable) {
        System.out.println("会话异常:" + throwable);
    }

    // 当接收到客户端发送的信息时触发的方法
    @OnMessage
    public void OnMessage(Session session, String message) throws Exception {
        Object userinfo = session.getUserProperties().get("id");
        Msg msg = buildMsg(userinfo, message, false);
        iMsgSender.send(msg);
    }

    /*private void sendAllMessage(String message) {
        onlines.values().forEach(s->{
            try {
                s.getBasicRemote().sendText(message);
            } catch (IOException e) {
                throw new RuntimeException("发送消息失败",e);
            }
        });
    }*/

    ObjectMapper objectMapper = new ObjectMapper();


    public Msg buildMsg(Object author, String content, boolean isOnlines){
        Msg msg = new Msg(author, content, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()),null);
        if(isOnlines == true){
            // 一个包含 所有在线用户 id 的一个集合
            List<Object> onlinesMap = onlines.values().
                    stream().
                    map(session -> session.getUserProperties().get("id")).
                    collect(Collectors.toList());
            msg.onlines = onlinesMap;
        }
        return msg;
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Msg{

        // 发送人
        Object author;
        // 内容
        String content;
        // 时间
        String time;
        // 下线人员列表
        List<Object> onlines;

        // 这里为什么不用类对象, 应为存入session中的数据是传给前端的, 所以不需要, 之前用类对象是因为那些用户数据是给后端用的
    }

    // 获取在线人数的集合
    public static Map<String, Session> getOnlines() {
        return onlines;
    }

    private Object getUserInfoById(String id) {
        String sql = "select * from %s where %s = ? ";
        sql = String.format(sql, websocktPropertise().getUserTable(), websocktPropertise().getKeyColumn());
        Map<String, Object> userinfo = jdbcTemplate.queryForMap(sql, id);
        return userinfo;
    }
}


